const STATE = {
    NOBIND : 1,
    READY : 2,
    RUNNING : 3,
    STOP : 4,
    PAUSE : 5
}
function enabledInHierarchy( node ){
    let scr = $T.getScr( node );
    if( scr && scr.enabledInHierarchy ){
        return true;
    }else if( !scr ){
        return true;
    }
    return false;
}

class Drag{
    constructor( node , params ){
        this.__state = STATE.NOBIND;
        if(!node || !node.isValid) return null;

        this.__ = {};
        this._node = node;

        params = params || {};
        this._initParams( params );

        node.on( cc.Node.EventType.TOUCH_START , this._start.bind(this) , this);
        this.__state = STATE.READY;
    }

    _initParams( p ){
        this._f = p ||{};
        let f = this._f;
        f.startCheck = f.startCheck ? f.startCheck : ()=>{return true};
        f.moveCheck = f.moveCheck ? f.moveCheck : ()=>{return true};
        f.cancelCheck = f.cancelCheck ? f.cancelCheck : ()=>{return true};
        f.endCheck = f.endCheck ? f.endCheck : ()=>{return true};

        f.startEventName = f.startEventName ? f.startEventName : "touch-Start";
        f.moveEventName = f.moveEventName ? f.moveEventName : "touch-Move";
        f.cancelEventName = f.cancelEventName ? f.cancelEventName : "touch-Cancel";
        f.endEventName = f.endEventName ? f.endEventName : "touch-End";
    }

    _start( e ){
        let _  = this.__ || {};
        let node = this._node;

        if( !enabledInHierarchy(node) ) return;

        if( this.isState( STATE.READY ) && this._f.startCheck(_ , e) ){
            //绑定执行事件
            this.offOrOnEvents( false , 'on' );
            _.startEvent = e;
            _.fxcode = 0;
            _.offsets = [0,0,0,0]; //上 右 下 左 的偏移量
            _.startNodePos = this._node.getPosition();
            this.setState( STATE.RUNNING );

            $T.trigger( node , this._f.startEventName , false , {event : e , param : _ })
        }
    }

    _move( e ){
        //如果状态不对，返回
        if ( !this.isState( STATE.RUNNING ) || !enabledInHierarchy(this._node)) return;
        let node = this._node;
        let _  = this.__;
        //cc.Node
        let start = e.getStartLocation();
        let cur = e.getLocation();
        if( !this._f.moveCheck( e , _ ) ) return;

        _.offsets[0] = cur.y>start.y ? (cur.y-start.y) : 0;
        _.offsets[1] = cur.x>start.x ? (cur.x-start.x) : 0;
        _.offsets[2] = start.y>cur.y ? (start.y-cur.y) : 0;
        _.offsets[3] = start.x>cur.x ? (start.x-cur.x) : 0;

        //console.log(_.offsets);
        if (cur.magSqr() > 20) {
            let x  = cur.x - start.x,
                y  = cur.y - start.y;
            //this._node.setPosition( cc.v2(_.startNodePos.x + x,_.startNodePos.y + y) );
            _.fxcode == 0 
                    ?  _.fxcode = this._getMoveFxCode( start , cur )
                    : (()=>{
                            let code = "0";
                            for(let i=0; i<_.offsets.length; i++){
                                if(_.offsets[i]>0){
                                    code += String(i+1);
                                }
                            }
                            return parseInt(code);
                        })()

            //console.log(fxcode);
            $T.trigger( node , 
                        this._f.moveEventName , 
                        false ,
                        {
                            event : e , 
                            param : _ , 
                            fxcode : _.fxcode,
                            pos:{ x:_.startNodePos.x + x, y:_.startNodePos.y + y}
                        })
        }

        e.stopPropagation();
    }

    _end( e ){
        if( !this._f.endCheck( e , this.__ ) ) return;
        let node = this._node;
        let _  = this.__;

        if( this.isState(STATE.RUNNING) ){
            this.setState(STATE.READY);
            this.offOrOnEvents( false , 'off' )

            $T.trigger( node , this._f.endEventName , false , {event : e , param : _ })
        }
    
        e.stopPropagation();
    }

    _getMoveFxCode( startPos , curPos){
        let xlen = Math.abs(curPos.x - startPos.x),
            ylen = Math.abs(curPos.y - startPos.y);

        if(xlen > ylen && xlen>30){
            return (curPos.x - startPos.x) > 0 ? 2 : 4;
        }else if( ylen > xlen && ylen>30){
            return (curPos.y - startPos.y) > 0 ? 1 : 3;
        }else{
            return 0;
        }
    }

    _cancel( e ){
        if( !this._f.cancelCheck( e , this.__ ) ) return;
        let node = this._node;
        let _  = this.__;

        if( this.isState(STATE.RUNNING) ){
            this.setState(STATE.READY);
            this.offOrOnEvents( false , 'off' )

            $T.trigger( node , this._f.cancelEventName , false , {event : e , param : _ })
        }
    
        e.stopPropagation();
    }

    isState(state){
        return this.__state === state;
    }

    setState(state){
        this.__state = state;
    }

    offOrOnEvents( isAll , meth ){
        if(!this._node || !this._node.isValid) return null;
        meth = meth || "off";

        if(meth == 'off'){
            isAll && this._node.off( cc.Node.EventType.TOUCH_START , this._start );
            this._node.off( cc.Node.EventType.TOUCH_MOVE , this._move );
            this._node.off( cc.Node.EventType.TOUCH_END , this._end );
            this._node.off( cc.Node.EventType.TOUCH_CANCEL , this._cancel );
        }else if(meth == 'on'){
            isAll && this._node.on( cc.Node.EventType.TOUCH_START , this._start.bind(this) , this );
            this._node.on( cc.Node.EventType.TOUCH_MOVE , this._move.bind(this) , this  );
            this._node.on( cc.Node.EventType.TOUCH_END , this._end.bind(this) , this  );
            this._node.on( cc.Node.EventType.TOUCH_CANCEL , this._cancel.bind(this) , this  );
        }
    }

    stop(){
        // cc.Node
        return new Promise(( res )=>{
            if( !this._node ){
                this.setState(STATE.STOP);
                res();
            }else{
                //解绑所有事件
                this.setState(STATE.STOP);
                this.offOrOnEvents( true , 'off');
                res();
            }
        });
    }
}


module.exports = Drag;  